package com.zed.api.common.resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * 基于文件系统的资源扫描器
 *
 * @author Zed
 */
public class FileSystemResourceScanner implements ResourceScanner<File> {

    private static final String PROTOCOL = "file";
    protected static final String SEPARATOR = "/";

    private Logger logger = LoggerFactory.getLogger(FileSystemResourceScanner.class);

    /**
     * 构造方法
     */
    public FileSystemResourceScanner() {

    }

    @Override
    public final File support(URL url) {
        if (PROTOCOL.equals(url.getProtocol())) {
            return this.getSupportFile(new File(url.getFile()));
        }
        return null;
    }

    /**
     * 获取所支持的文件
     *
     * @param file {@link File}
     * @return {@link File}
     */
    protected File getSupportFile(File file) {
        return file;
    }

    @Override
    public final void scanning(File instance, String resourceDir, Predicate<String> filter, boolean subdirectory,
                               ResourceScanningCallback callback) {
        Objects.requireNonNull(instance, "\"instance\" cannot be null.");
        Objects.requireNonNull(resourceDir, "\"resourceDir\" cannot be null.");
        Objects.requireNonNull(filter, "\"filter\" cannot be null.");
        Objects.requireNonNull(callback, "\"callback\" cannot be null.");

        File dir = instance;
        if (resourceDir != null) {
            String path = resourceDir.replace("\\", "/");
            if (path.startsWith(SEPARATOR)) {
                path = path.substring(1);
            }

            dir = new File(dir, path);
        }
        this.doScanning(dir, null, filter, subdirectory, callback);
    }

    /**
     * 执行扫描
     *
     * @param dir          {@link File},目录
     * @param path         {@link String}, 相对路径
     * @param filter       {@link Predicate},过滤条件
     * @param subDirectory {@link boolean}, 是否递归扫描子目录
     * @param callback     {@link ResourceScanningCallback},回调接口
     */
    protected void doScanning(File dir, String path, Predicate<String> filter, boolean subDirectory,
                              ResourceScanningCallback callback) {
        File[] files = dir.listFiles();
        if (files == null) return;

        for (File file : files) {
            if (file.isDirectory()) {
                if (subDirectory) {
                    String dirPath = path == null ? file.getName() : path.concat(SEPARATOR).concat(file.getName());
                    doScanning(file, dirPath, filter, subDirectory, callback);
                }
            } else {
                String filePath = path == null ? file.getName() : path.concat(SEPARATOR).concat(file.getName());
                if (filter.test(filePath)) {
                    try {
                        callback.onFound(filePath, file.toURI().toURL());
                    } catch (MalformedURLException e) {
                        if (logger.isErrorEnabled()) {
                            logger.error(e.getMessage(), e);
                        }
                    }
                }

            }
        }
    }

    @Override
    public String toString() {
        return "FileSystemResourceScanner";
    }
}
